﻿<template>
  <div class="entity-manager">
    <section class="page-header">
      <div>
        <h1>{{ entityConfig.displayName }}管理</h1>
        <p v-if="entityConfig.tableComment">{{ entityConfig.tableComment }}</p>
      </div>
      <div class="page-meta">
        <span>表名：{{ entityConfig.tableName }}</span>
        <span>字段数：{{ entityConfig.fields.length }}</span>
      </div>
    </section>

    <section class="toolbar">
      <div class="toolbar-left">
        <el-button type="primary" @click="handleCreate">
          <el-icon><Plus /></el-icon>
          新增
        </el-button>
        <el-button type="danger" :disabled="!selectedRows.length" @click="handleBatchDelete">
          <el-icon><Delete /></el-icon>
          批量删除
        </el-button>
      </div>
      <div class="toolbar-right">
        <el-button text @click="loadData">刷新</el-button>
      </div>
    </section>

    <el-table
      ref="tableRef"
      v-loading="loading"
      :data="tableData"
      @selection-change="handleSelectionChange"
      class="entity-table"
    >
      <el-table-column type="selection" width="55" />

      <el-table-column
        v-for="field in tableFields"
        :key="field.name"
        :prop="field.name"
        :label="field.label"
        :show-overflow-tooltip="field.showOverflow"
      >
        <template v-if="field.type === FieldType.BOOLEAN" #default="{ row }">
          <el-tag :type="row[field.name] ? 'success' : 'info'">
            {{ row[field.name] ? '是' : '否' }}
          </el-tag>
        </template>
        <template v-else-if="field.isDate" #default="{ row }">
          {{ formatDate(row[field.name]) }}
        </template>
      </el-table-column>

      <el-table-column label="操作" width="200" fixed="right">
        <template #default="{ row }">
          <el-button size="small" @click="handleView(row)">查看</el-button>
          <el-button size="small" type="primary" @click="handleEdit(row)">编辑</el-button>
          <el-button size="small" type="danger" @click="handleDelete(row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>

    <el-pagination
      v-model:current-page="pagination.current"
      v-model:page-size="pagination.size"
      :total="pagination.total"
      :page-sizes="[10, 20, 50, 100]"
      layout="total, sizes, prev, pager, next, jumper"
      @size-change="loadData"
      @current-change="loadData"
      class="pagination-bar"
    />

    <el-dialog
      v-model="formVisible"
      :title="formTitle"
      width="620px"
      :close-on-click-modal="false"
    >
      <el-form
        ref="formRef"
        :model="formData"
        :rules="formRules"
        label-width="120px"
        :disabled="formAction === FormAction.VIEW"
      >
        <el-form-item
          v-for="field in formFields"
          :key="field.name"
          :label="field.label"
          :prop="field.name"
        >
          <component
            :is="field.component"
            v-model="formData[field.name]"
            v-bind="field.componentProps"
            :placeholder="field.placeholder"
          />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="formVisible = false">取消</el-button>
        <el-button
          v-if="formAction !== FormAction.VIEW"
          type="primary"
          :loading="submitting"
          @click="handleFormSubmit"
        >
          确认
        </el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed, onMounted } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { Plus, Delete } from '@element-plus/icons-vue'
import type { EntityConfig, EntityData, FormAction } from '@/types/entity'
import { FieldType } from '@/types/entity'
import { createEntityApi } from '@/api/base'
import { formatDate } from '@/utils/formatUtils'

interface Props {
  entityConfig: EntityConfig
}

const props = defineProps<Props>()

const tableRef = ref()
const formRef = ref()

const loading = ref(false)
const tableData = ref<EntityData[]>([])
const selectedRows = ref<EntityData[]>([])

const pagination = reactive({
  current: 1,
  size: 20,
  total: 0
})

const formVisible = ref(false)
const formAction = ref<FormAction>(FormAction.CREATE)
const formData = ref<EntityData>({})
const submitting = ref(false)

const api = createEntityApi(props.entityConfig.tableName, props.entityConfig.hasCompositePrimaryKey)

const tableFields = computed(() => props.entityConfig.fields
  .filter(field => field.showInTable !== false)
  .map(field => ({
    name: field.name,
    label: field.label,
    type: field.type,
    isDate: field.type === FieldType.LOCAL_DATE || field.type === FieldType.LOCAL_TIME || field.type === FieldType.LOCAL_DATE_TIME,
    showOverflow: field.type === FieldType.STRING && (field.maxLength || 0) > 100
  })))

const formFields = computed(() => props.entityConfig.fields
  .filter(field => field.showInForm !== false && !field.autoIncrement)
  .map(field => ({
    ...field,
    component: resolveComponent(field.type),
    componentProps: buildComponentProps(field),
    placeholder: `请输入${field.label}`
  })))

const formTitle = computed(() => {
  const titleMap: Record<FormAction, string> = {
    create: `新增${props.entityConfig.displayName}`,
    update: `编辑${props.entityConfig.displayName}`,
    view: `查看${props.entityConfig.displayName}`
  }
  return titleMap[formAction.value]
})

const formRules = computed(() => {
  const rules: Record<string, any[]> = {}
  props.entityConfig.fields.forEach(field => {
    if (field.autoIncrement || field.showInForm === false) {
      return
    }
    const fieldLabel = field.label || field.name
    const validators: any[] = []

    if (field.required) {
      validators.push({
        required: true,
        message: `${fieldLabel}不能为空`,
        trigger: field.type === FieldType.BOOLEAN ? 'change' : 'blur'
      })
    }

    if (field.type === FieldType.STRING && field.maxLength) {
      validators.push({
        max: field.maxLength,
        message: `${fieldLabel}最多输入${field.maxLength}个字符`,
        trigger: 'blur'
      })
    }

    if (field.type === FieldType.INTEGER || field.type === FieldType.LONG) {
      validators.push({
        type: 'number',
        message: `${fieldLabel}必须为整数`,
        trigger: 'change'
      })
    }

    if (field.type === FieldType.DOUBLE || field.type === FieldType.BIG_DECIMAL) {
      validators.push({
        validator: createDecimalValidator(field, fieldLabel),
        trigger: 'change'
      })
    }

    if (validators.length) {
      rules[field.name] = validators
    }
  })
  return rules
})

onMounted(() => {
  loadData()
})

async function loadData() {
  loading.value = true
  try {
    const result = await api.findByPage({
      current: pagination.current,
      size: pagination.size
    })
    tableData.value = result.records || []
    pagination.total = result.total || 0
  } catch (error) {
    console.error('加载数据失败:', error)
    ElMessage.error('加载数据失败')
  } finally {
    loading.value = false
  }
}

function handleSelectionChange(selection: EntityData[]) {
  selectedRows.value = selection
}

function handleCreate() {
  formAction.value = FormAction.CREATE
  formData.value = {}
  formVisible.value = true
}

function handleView(row: EntityData) {
  formAction.value = FormAction.VIEW
  formData.value = { ...row }
  formVisible.value = true
}

function handleEdit(row: EntityData) {
  formAction.value = FormAction.UPDATE
  formData.value = { ...row }
  formVisible.value = true
}

async function handleDelete(row: EntityData) {
  try {
    await ElMessageBox.confirm('确定要删除该条记录吗？', '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })

    if (props.entityConfig.hasCompositePrimaryKey) {
      await api.deleteById(row)
    } else {
      const primaryKey = getPrimaryKeyField()
      await api.deleteById(row[primaryKey.name])
    }

    ElMessage.success('删除成功')
    loadData()
  } catch (error) {
    if (error !== 'cancel') {
      console.error('删除失败:', error)
      ElMessage.error('删除失败')
    }
  }
}

async function handleBatchDelete() {
  try {
    await ElMessageBox.confirm(`确定要删除选中的 ${selectedRows.value.length} 条记录吗？`, '提示', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    })

    if (props.entityConfig.hasCompositePrimaryKey) {
      await api.deleteAll(selectedRows.value)
    } else {
      const primaryKey = getPrimaryKeyField()
      const ids = selectedRows.value.map(row => row[primaryKey.name])
      await api.deleteAll(ids)
    }

    ElMessage.success('批量删除成功')
    loadData()
  } catch (error) {
    if (error !== 'cancel') {
      console.error('批量删除失败:', error)
      ElMessage.error('批量删除失败')
    }
  }
}

async function handleFormSubmit() {
  if (!formRef.value) {
    return
  }

  try {
    await formRef.value.validate()
    submitting.value = true

    if (formAction.value === FormAction.CREATE) {
      await api.create(formData.value)
      ElMessage.success('创建成功')
    } else if (formAction.value === FormAction.UPDATE) {
      if (props.entityConfig.hasCompositePrimaryKey) {
        await api.update(null, formData.value)
      } else {
        const primaryKey = getPrimaryKeyField()
        await api.update(formData.value[primaryKey.name], formData.value)
      }
      ElMessage.success('更新成功')
    }

    formVisible.value = false
    loadData()
  } catch (error) {
    console.error('操作失败:', error)
    ElMessage.error('操作失败')
  } finally {
    submitting.value = false
  }
}

function getPrimaryKeyField() {
  const field = props.entityConfig.fields.find(item => item.primaryKey)
  if (!field) {
    throw new Error('未找到主键字段')
  }
  return field
}

function resolveComponent(type: FieldType) {
  switch (type) {
    case FieldType.BOOLEAN:
      return 'el-switch'
    case FieldType.INTEGER:
    case FieldType.LONG:
    case FieldType.DOUBLE:
    case FieldType.BIG_DECIMAL:
      return 'el-input-number'
    case FieldType.LOCAL_DATE:
      return 'el-date-picker'
    case FieldType.LOCAL_TIME:
      return 'el-time-picker'
    case FieldType.LOCAL_DATE_TIME:
      return 'el-date-picker'
    default:
      return 'el-input'
  }
}

function buildComponentProps(field: any) {
  const base: Record<string, any> = {
    style: { width: '100%' }
  }

  switch (field.type) {
    case FieldType.BOOLEAN:
      base.activeText = '是'
      base.inactiveText = '否'
      break
    case FieldType.INTEGER:
    case FieldType.LONG:
      base.min = 0
      base.controlsPosition = 'right'
      break
    case FieldType.DOUBLE:
    case FieldType.BIG_DECIMAL:
      base.min = 0
      base.controlsPosition = 'right'
      base.precision = field.scale || 2
      break
    case FieldType.LOCAL_DATE:
      base.type = 'date'
      base.valueFormat = 'YYYY-MM-DD'
      base.clearable = true
      break
    case FieldType.LOCAL_TIME:
      base.isRange = false
      base.valueFormat = 'HH:mm:ss'
      base.clearable = true
      break
    case FieldType.LOCAL_DATE_TIME:
      base.type = 'datetime'
      base.valueFormat = 'YYYY-MM-DD HH:mm:ss'
      base.clearable = true
      break
    default:
      if (field.maxLength && field.maxLength > 255) {
        base.type = 'textarea'
        base.rows = 3
      }
  }

  return base
}

function createDecimalValidator(field: any, label: string) {
  return (_: unknown, value: unknown, callback: (error?: Error) => void) => {
    if (value === null || value === undefined || value === '') {
      callback()
      return
    }
    const scale = field.scale || 2
    const pattern = new RegExp(`^\\d+(?:\\.\\d{0,${scale}})?$`)
    if (!pattern.test(String(value))) {
      callback(new Error(`${label}最多保留${scale}位小数`))
      return
    }
    callback()
  }
}
</script>

<style scoped>
.entity-manager {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.page-header {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  padding: 24px;
  background: #ffffff;
  border: 1px solid #e4e7ed;
  border-radius: 16px;
  box-shadow: 0 4px 20px rgba(15, 23, 42, 0.08);
}

.page-header h1 {
  margin: 0 0 8px 0;
  font-size: 22px;
  color: #1f2937;
}

.page-header p {
  margin: 0;
  font-size: 13px;
  color: #6b7280;
}

.page-meta {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 12px;
  color: #6b7280;
}

.toolbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  background: #ffffff;
  border: 1px solid #e4e7ed;
  border-radius: 16px;
  box-shadow: 0 4px 20px rgba(15, 23, 42, 0.06);
}

.toolbar-left {
  display: flex;
  align-items: center;
  gap: 12px;
}

.toolbar-right {
  display: flex;
  align-items: center;
  gap: 12px;
}

.entity-table {
  border-radius: 16px;
  overflow: hidden;
  background: #ffffff;
}

.pagination-bar {
  display: flex;
  justify-content: flex-end;
  background: #ffffff;
  padding: 12px 16px;
  border-radius: 16px;
  border: 1px solid #e4e7ed;
}

@media (max-width: 768px) {
  .page-header {
    flex-direction: column;
    gap: 12px;
  }

  .toolbar {
    flex-direction: column;
    gap: 12px;
    align-items: stretch;
  }

  .toolbar-right {
    justify-content: flex-start;
  }
}
</style>
